package com.duolebo.uteped_sdk.remind;

import static android.content.Context.MEDIA_SESSION_SERVICE;

import android.annotation.SuppressLint;
import android.app.Notification;
import android.content.ComponentName;
import android.content.Context;
import android.media.AudioManager;
import android.media.MediaMetadata;
import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.media.session.MediaSessionManager;
import android.media.session.PlaybackState;
import android.os.Bundle;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.duolebo.uteped_sdk.UTEPedBleClientHelper;
import com.duolebo.uteped_sdk.UTEPedMethodCallHandler;
import com.duolebo.uteped_sdk.service.UTEPedNotificationService;
import com.duolebo.uteped_sdk.utils.Const;
import com.duolebo.uteped_sdk.utils.Logger;
import com.duolebo.uteped_sdk.utils.SPHelper;
import com.duolebo.uteped_sdk.utils.Tools;
import com.yc.nadalsdk.bean.MusicAppPlayInfo;
import com.yc.nadalsdk.bean.MusicAppStatus;
import com.yc.nadalsdk.bean.MusicDeviceControl;
import com.yc.nadalsdk.bean.Notify;
import com.yc.nadalsdk.ble.open.UteBleDevice;
import com.yc.nadalsdk.constants.NotifyType;
import com.yc.nadalsdk.listener.BleConnectStateListener;

import java.util.List;

/**
 * @Author: LiuYang
 * @Date: 2023/12/26 21:45
 * @Description:
 */
public class MusicRemind extends BaseRemind implements BleConnectStateListener {

    private final static String TAG = "MusicRemind";
    private static final String VOLUME_PREF_MUTE = "volume_pref_mute";
    private static final String VOLUME_PREF_VALUE = "volume_pref_value";

    private List<MediaController> activeSessions;
    private MediaController.Callback sessionCallback;

    private MediaController currentMediaController;
    private AudioManager audioManager = null;

    private boolean isInit = false;
    private int currVolume = 0;
    private int playerState = PlaybackState.STATE_NONE;
    private static final int VOLUME_DELTA = 1;
    private static final int VOLUME_MAX = 20;
    private static final int VOLUME_MIN = 0;
    private final MusicAppPlayInfo musicAppPlayInfo = new MusicAppPlayInfo();

    @SuppressLint("StaticFieldLeak")
    private static MusicRemind instance;
    public static MusicRemind getInstance(Context context) {
        if (instance == null) {
            instance = new MusicRemind(context);
        }

        return instance;
    }

    public static MusicRemind shareInstance() {
        return instance;
    }

    public MusicRemind(Context context) {
        super(context);
        initVolume();
        UTEPedBleClientHelper.shareInstance().addBleConnectStateListener(this);
    }

    public void init() {
        Logger.d(TAG, "init...");
        if (isInit) {
            return;
        }

        this.isInit = true;
        initMediaSessionManager();
        registerSessionCallbacks();
    }

    public void onNotificationPosted(StatusBarNotification sbn) {
        Logger.d(TAG, "onNotificationPosted...");
        Bundle extras = sbn.getNotification().extras;
        MediaSession.Token token = extras.getParcelable(Notification.EXTRA_MEDIA_SESSION);
        if (token != null) {
            currentMediaController = new MediaController(context, token);
        }
        else {
            Logger.d(TAG, "token is null!");
        }
    }

    private void initVolume() {
        audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        currVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
    }

    private void initMediaSessionManager() {
        MediaSessionManager mediaSessionManager = (MediaSessionManager) context.getSystemService(MEDIA_SESSION_SERVICE);
        ComponentName localComponentName = new ComponentName(context, UTEPedNotificationService.class);
        mediaSessionManager.addOnActiveSessionsChangedListener(new MediaSessionManager.OnActiveSessionsChangedListener() {
            @Override
            public void onActiveSessionsChanged(@Nullable final List<MediaController> controllers) {
                assert controllers != null;
                for (MediaController mediaController : controllers) {
                    String packageName = mediaController.getPackageName();
                    Log.e(TAG, "MyApplication onActiveSessionsChanged mediaController.getPackageName: " + packageName);
                    synchronized (this) {
                        activeSessions = controllers;
                        registerSessionCallbacks();
                    }
                }
            }
        }, localComponentName);
        synchronized (this) {
            activeSessions = mediaSessionManager.getActiveSessions(localComponentName);
            registerSessionCallbacks();
        }
    }

    private void registerSessionCallbacks() {
        for (MediaController controller : activeSessions) {
            if (sessionCallback == null) {
                sessionCallback = new MediaController.Callback() {
                    @Override
                    public void onMetadataChanged(MediaMetadata metadata) {
                        if (metadata != null) {
                            String trackName = metadata.getString(MediaMetadata.METADATA_KEY_TITLE);
                            String artistName = metadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
                            String albumArtistName = metadata.getString(MediaMetadata.METADATA_KEY_ALBUM_ARTIST);
                            String albumName = metadata.getString(MediaMetadata.METADATA_KEY_ALBUM);
                            long duration = metadata.getLong(MediaMetadata.METADATA_KEY_DURATION);
                            Log.i(TAG, "---------------------------------");
                            Log.i(TAG, "| trackName: " + trackName);
                            Log.i(TAG, "| artistName: " + artistName);
                            Log.i(TAG, "| albumArtistName: " + albumArtistName);
                            Log.i(TAG, "| albumName: " + albumName);
                            Log.i(TAG, "| duration: " + duration);
                            Log.i(TAG, "---------------------------------");

                            // 少于10s忽略
                            if (duration > 1000 * 10) {
                                String singerName = artistName;
                                if (!TextUtils.isEmpty(albumArtistName))
                                    singerName += ("-" + albumArtistName);
                                musicAppPlayInfo.setSingerName(singerName);

                                String songName = trackName;
                                if (!TextUtils.isEmpty(albumName))
                                    songName += ("-" + albumName);

                                musicAppPlayInfo.setSongName(songName);
                                uteBleConnection.setMusicAppPlayInfo(musicAppPlayInfo);
                            }
                        }
                    }

                    @Override
                    public void onPlaybackStateChanged(PlaybackState state) {
                        if (state != null) {
                            playerState = state.getState();
                            musicAppPlayInfo.setPlayState(playerState);
                            Log.e(TAG, "MediaController.Callback onPlaybackStateChanged: ");
                            reportPlayerStatus();
                        }
                    }
                };
            }
            controller.registerCallback(sessionCallback);
        }
    }

    @Override
    public void onNotify(@NonNull UteBleDevice uteBleDevice, @NonNull Notify notify) {
        if (notify.getType() == NotifyType.MUSIC_APP_STATUS && !Tools.isNotificationListenerEnabled(Tools.getApplicationContext())) {
            UTEPedMethodCallHandler.shareInstance().publishLocal(Const.ACTION_APP_NOTIFICATION_CHECK, "");
        }

        if (!isInit) {
            return;
        }

        int eventType = notify.getType();
        switch (eventType) {
            case NotifyType.MUSIC_APP_STATUS:
                reportPlayerStatus();
                break;

            case NotifyType.MUSIC_DEVICE_CONTROL:
                MusicDeviceControl deviceControl = (MusicDeviceControl) notify.getData();
                onMusicControl(deviceControl.getControl());
                break;

            case NotifyType.MUSIC_DEVICE_FILE_INFO:
                this.uteBleConnection.setMusicAppPlayInfo(musicAppPlayInfo);
                break;

            default:
        }
    }

    private void reportPlayerStatus() {
        int status = MusicAppStatus.STATUS_PERMISSION_DENIED;
        if (this.isInit) {
            switch (playerState) {
                case PlaybackState.STATE_PAUSED:
                case PlaybackState.STATE_PLAYING:
                case PlaybackState.STATE_BUFFERING:
                case PlaybackState.STATE_SKIPPING_TO_PREVIOUS:
                case PlaybackState.STATE_SKIPPING_TO_NEXT:
                case PlaybackState.STATE_SKIPPING_TO_QUEUE_ITEM:
                    status = MusicAppStatus.STATUS_SUCCESS;
                    break;

                case PlaybackState.STATE_STOPPED:
                case PlaybackState.STATE_ERROR:
                case PlaybackState.STATE_NONE:
                    status = MusicAppStatus.STATUS_NO_MUSIC_PLAYING;
                    break;

            }
        }
        musicAppPlayInfo.setMaxVolume(audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC));
        musicAppPlayInfo.setCurrentVolume(audioManager.getStreamVolume(AudioManager.STREAM_MUSIC));
        this.uteBleConnection.setMusicAppStatus(status);
        this.uteBleConnection.setMusicAppPlayInfo(musicAppPlayInfo);
    }

    public void toggleMute() {
        setVolume(!SPHelper.shareInstance().getBoolean(VOLUME_PREF_MUTE, false), true);
    }

    private void setVolume(boolean mute, boolean recover) {
        SPHelper.shareInstance().putAndCommit(VOLUME_PREF_MUTE, mute);

        if (mute) {
            SPHelper.shareInstance().putAndCommit(VOLUME_PREF_VALUE, currVolume);
            currVolume = 0;
        } else {
            if (recover) {
                currVolume = SPHelper.shareInstance().getInt(VOLUME_PREF_VALUE, currVolume);
            }
        }

        setVolume(currVolume);
    }

    private void setVolume(int volume) {
//        audioManager.adjustSuggestedStreamVolume(AudioManager.ADJUST_SAME, AudioManager.STREAM_MUSIC, 0);
        audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, AudioManager.FLAG_SHOW_UI);
//        audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, volume > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER, 0);
    }

    private void onMusicControl(int option) {
        MediaController controller = currentMediaController;
        if (currentMediaController == null && activeSessions != null) {
            for (MediaController session: activeSessions) {
                controller = session;
                break;
            }
        }

        if (controller == null) {
            return;
        }

        MediaController.TransportControls controls = controller.getTransportControls();

        switch (option) {
            case MusicDeviceControl.CONTROL_MUSIC_PLAYER:
                if (playerState != PlaybackState.STATE_PLAYING) {
                    controls.play();
                    Logger.d(TAG, "resume play");
                }
                else {
                    Logger.d(TAG, "music is already on playing status.");
                }

                break;
            case MusicDeviceControl.CONTROL_MUSIC_PAUSE:
                if (playerState == PlaybackState.STATE_PLAYING || playerState == PlaybackState.STATE_BUFFERING) {
                    controls.pause();
                }
                break;
            case MusicDeviceControl.CONTROL_MUSIC_TO_PREVIOUS:
                controls.skipToPrevious();
                break;
            case MusicDeviceControl.CONTROL_MUSIC_TO_NEXT:
                controls.skipToNext();
                break;
            case MusicDeviceControl.CONTROL_VOLUME_INCREASE:
            case MusicDeviceControl.CONTROL_VOLUME_REDUCTION:
                int posOrNeg = (option == MusicDeviceControl.CONTROL_VOLUME_INCREASE) ? 1 : -1;
                currVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
                if (VOLUME_MIN <= currVolume && currVolume <= VOLUME_MAX) {
                    int newVolume = VOLUME_DELTA * posOrNeg + currVolume;
                    setVolume(newVolume);
                    reportPlayerStatus();
                }
//                if (option == MusicDeviceControl.CONTROL_VOLUME_INCREASE) {
//                    controller.dispatchMediaButtonEvent(new KeyEvent(100, 100, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_VOLUME_UP, 0));
//                    controller.dispatchMediaButtonEvent(new KeyEvent(100, 100, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_VOLUME_UP, 0));
//                }
//                else {
//                    controller.dispatchMediaButtonEvent(new KeyEvent(100, 100, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_VOLUME_DOWN, 0));
//                    controller.dispatchMediaButtonEvent(new KeyEvent(100, 100, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_VOLUME_DOWN, 0));
//                }
                break;
            case MusicDeviceControl.CONTROL_VOLUME_NO:
                // 手表固件随意触发此事件，屏蔽
//                toggleMute();
                break;

            default:
        }
    }

    @Override
    public void onConnecteStateChange(int status) {
        switch (status) {
            case STATE_CONNECTED:
                this.uteBleConnection.setMusicAppStatus(MusicAppStatus.STATUS_NO_MUSIC_PLAYING);
                break;

            case STATE_DISCONNECTED:
                this.uteBleConnection.setMusicAppStatus(MusicAppStatus.STATUS_PERMISSION_DENIED);
                break;
        }
    }
}
